package org.springcloud.plugin.framework.decorator;

import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAvoidanceRule;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springcloud.plugin.common.entity.WeightFilterEntity;
import org.springcloud.plugin.framework.adapter.CoreAdapter;
import org.springcloud.plugin.framework.loadbalance.weight.RuleMapWeightRandomLoadBalance;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Author yanggld
 * @Date 2019/12/17-18:06
 * @Description
 */
@Slf4j
public class ZoneAvoidanceRuleDecorator extends ZoneAvoidanceRule {

	@Autowired
	private CoreAdapter coreAdapter;

	private RuleMapWeightRandomLoadBalance ruleMapWeightRandomLoadBalance;
	//TODO 负载均衡重试
	private boolean retryEnabled =false;
	private int retryAwaitTime =2;
	private int retryTimes =2;

	@PostConstruct
	private void initialize() {
		ruleMapWeightRandomLoadBalance = new RuleMapWeightRandomLoadBalance(coreAdapter);
	}


	@Override
	public Server choose(Object key) {
		WeightFilterEntity ruleWeightFilterEntity = ruleMapWeightRandomLoadBalance.getT();
		if (ruleWeightFilterEntity != null && ruleWeightFilterEntity.hasWeight()) {
			List<Server> serverList = retryEnabled ? getRetryableServerList(key) : getServerList(key);
			boolean isWeightChecked = true;
			//TODO check
//			boolean isWeightChecked = ruleMapWeightRandomLoadBalance.checkWeight(serverList, ruleWeightFilterEntity);
			if (isWeightChecked) {
				try {
					Server server = ruleMapWeightRandomLoadBalance.choose(serverList, ruleWeightFilterEntity);
					String consumerServiceId = coreAdapter.getServiceId();
					log.info(consumerServiceId+"------>>>>>>-------应用权重路由");
					return server;
				} catch (Exception e) {
					log.error("Execute rule weight-random-loadbalance failed, it will use default loadbalance", e);
					return super.choose(key);
				}
			} else {
				return super.choose(key);
			}
		}
		return super.choose(key);
	}

	// 必须执行getEligibleServers，否则叠加执行权重规则和版本区域策略会失效
	private List<Server> getServerList(Object key) {
		List<Server> allServers = getLoadBalancer().getAllServers();
		List<Server> eligibleServers = getPredicate().getEligibleServers(allServers, key);
		return eligibleServers;
	}

	private List<Server> getRetryableServerList(Object key) {
		List<Server> serverList = getServerList(key);
		for (int i = 0; i < retryTimes; i++) {
			if (CollectionUtils.isNotEmpty(serverList)) {
				break;
			}
			try {
				TimeUnit.MILLISECONDS.sleep(retryAwaitTime);
			} catch (InterruptedException e) {
			}
			log.info("Retry to get server list for {} times...", i + 1);
			serverList = getServerList(key);
		}
		return serverList;
	}
}
